home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / text / misc / psgrind.lha / pfontedp.c < prev    next >
C/C++ Source or Header  |  1993-04-09  |  20KB  |  846 lines

  1. /* pfontedpr - general purpose "pretty printer".
  2.  *
  3.  * This version is a hacked up version of tfontedpr.c as obtained from
  4.  * the following people
  5.  *
  6.  * Copyright (C) 1985 by Van Jacobson, Lawrence Berkeley Laboratory.
  7.  * This program may be freely used and copied but may not be sold
  8.  * without the author's written permission.  This notice must remain
  9.  * in any copy or derivative.
  10.  *
  11.  * This program is used as part of the "tgrind" shell script.  It
  12.  * converts program source file(s) to TeX input files.
  13.  *
  14.  * This program is an adaptation of "vfontedpr" v4.2 (12/11/84) from
  15.  * the 4.2bsd Unix distribution.  Vfontedpr was written by Dave
  16.  * Presotto (based on an earlier program of the same name written by
  17.  * Bill Joy).
  18.  *
  19.  * I would welcome comments, enhancements, bug fixes, etc.  Please 
  20.  * mail them to:
  21.  *    van@lbl-rtsg.arpa    (from arpanet, milnet, csnet, etc.)
  22.  *    ..!ucbvax!lbl-csam!van    (from Usenet/UUCP)
  23.  *
  24.  * Modifications.
  25.  * --------------
  26.  *  8Apr93  Dylan McNamee (dylan@cs.washington.edu)  
  27.  *            Modernized the code.  Now passes ANSI without warnings.
  28.  * 30Mar85  Chris & Van: Fixed "\C" & "\S" (comment & string start indicators)
  29.  *            to really appear at the start of comments & strings.
  30.  *            Changes for speeded-up expmatch.
  31.  * 29Mar85  Chris Torek (chris@maryland):  Bug fixes for '~' and '^L'
  32.  *            output.  Most cpu-time eaters recoded to improve
  33.  *            efficiency.
  34.  * 10Feb85  Van        Written.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <ctype.h>
  39.  
  40. #include    <stdlib.h>
  41. #include    <string.h>
  42. #include    <time.h>
  43. #ifdef    MSDOS
  44. extern char     *asctime();
  45. #else
  46.  
  47. #include    <sys/types.h>
  48. #include    <sys/stat.h>
  49. #endif
  50.  
  51. #define    DBUFSIZ    2048
  52. #define boolean int
  53. #define TRUE 1
  54. #define FALSE 0
  55. #define NIL 0
  56. #define STANDARD 0
  57. #define ALTERNATE 1
  58.  
  59. #define STRLEN 10        /* length of strings introducing things */
  60. #define PNAMELEN 80        /* length of a function/procedure name */
  61. #define PSMAX 20        /* size of procedure name stacking */
  62.  
  63. /* regular expression routines */
  64.  
  65. char    *expmatch(char *, char *, char **, char *);        
  66.                 /* match a string to an expression */
  67. char    *convexp(char *);    /* convert expression to internal form */
  68. char    *tgetstr();
  69. void    putstr(char *cp);
  70. int     tgetent(char *, char *, char *);
  71. char    *tgetstr(char *, char **);
  72. int     tgetflag(char *);
  73. void    sinitfile(void);
  74. void    outchar(char c);
  75. int     outpsstring(char *);
  76. void    putKcp(char *, char *, boolean);
  77. void    putScp(char *);
  78. boolean    isproc(char *);
  79. int     width(char *, char *);
  80. int     iskw(char *);
  81. int     modechange(int);
  82. void    charmode(void);
  83.  
  84. /*
  85.  *    The state variables
  86.  */
  87.  
  88. #define    _SMODE    1
  89. #define    _SHMODE    2
  90. #define    _KMODE    3
  91. #define    _CMODE    4
  92. #define    _NMODE    5
  93.  
  94. boolean    incomm;            /* in a comment of the primary type */
  95. boolean    instr;            /* in a string constant */
  96. boolean    inchr;            /* in a string constant */
  97. boolean    nokeyw = FALSE;        /* no keywords being flagged */
  98. boolean prccont;        /* continue last procedure */
  99. int    comtype;        /* type of comment */
  100. int    psptr;            /* the stack index of the current procedure */
  101. char    pstack[PSMAX][PNAMELEN+1];    /* the procedure name stack */
  102. int    plstack[PSMAX];        /* the procedure nesting level stack */
  103. int    blklevel;        /* current nesting level */
  104. char    *defsfile = {DEFSFILE}; /* name of language definitions file */
  105. char    pname[DBUFSIZ+1];
  106.  
  107. /*
  108.  *    The language specific globals
  109.  */
  110.  
  111. char    *language = "c";    /* the language indicator */
  112. char    *l_keywds[DBUFSIZ/2];    /* keyword table address */
  113. char    *l_prcbeg;        /* regular expr for procedure begin */
  114. char    *l_combeg;        /* string introducing a comment */
  115. char    *l_comend;        /* string ending a comment */
  116. char    *l_acmbeg;        /* string introducing a comment */
  117. char    *l_acmend;        /* string ending a comment */
  118. char    *l_blkbeg;        /* string begining of a block */
  119. char    *l_blkend;        /* string ending a block */
  120. char    *l_strbeg;        /* delimiter for string constant */
  121. char    *l_strend;        /* delimiter for string constant */
  122. char    *l_chrbeg;        /* delimiter for character constant */
  123. char    *l_chrend;        /* delimiter for character constant */
  124. char    l_escape;        /* character used to escape characters */
  125. boolean    l_toplex;        /* procedures only defined at top lex level */
  126. boolean    l_onecase;        /* upper & lower case equivalent */
  127.  
  128. int    charmflag,reallnum,outlnum,procout;
  129. char    *ignoredef;        /* if set ignore this define    */
  130. int    inignore,wide;        /* if set do wide printout    */
  131.  
  132. /*
  133.  *  global variables also used by expmatch
  134.  */
  135. extern    boolean    rescaped;    /* if last character was an escape */
  136. extern    char *rstart;        /* start of the current string */
  137.  
  138. int    (*re_strncmp)(const char *, const char *, size_t);
  139.                 /* function to do string compares */
  140. extern    int strncmp();
  141. extern    int lc_strncmp();
  142.  
  143. /*
  144.  * The following table converts ASCII characters to a printed
  145.  * representation, taking care of all the TeX quoting.  N.B.: all
  146.  * single-character strings are assumed to be equivalent to the
  147.  * character for that index (i.e., printtab['c'] can't be "f").
  148.  * (This is purely for efficiency hacking.)
  149.  */
  150. char *printtab[128] = {
  151.     "\0x",   "\\^A",  "\\^B",  "\\^C",  "\\^D",  "\\^E",  "\\^F",  "\\^G",
  152.     "\\^H",  "\t",    "}}\n",  "\\^K",  "\0x",   "\\^M",  "\\^N",  "\\^O",
  153.     "\\^P",  "\\^Q",  "\\^R",  "\\^S",  "\\^T",  "\\^U",  "\\^V",  "\\^W",
  154.     "\\^X",  "\\^Y",  "\\^Z",  "\\^[",  "\\^\\!","\\^]",  "\\^\\^","\\^_",
  155.     " ",     "!",     "\\\"",  "\\#",   "\\$",   "\\%",   "\\&",   "\\'",
  156.     "(",     ")",     "*",     "+",     ",",     "\\-",   ".",     "\\/",
  157.     "0",     "1",     "2",     "3",     "4",     "5",     "6",     "7",
  158.     "8",     "9",     ":",     ";",     "\\<",   "=",     "\\>",   "?",
  159.     "@",     "A",     "B",     "C",     "D",     "E",     "F",     "G",
  160.     "H",     "I",     "J",     "K",     "L",     "M",     "N",     "O",
  161.     "P",     "Q",     "R",     "S",     "T",     "U",     "V",     "W",
  162.     "X",     "Y",     "Z",     "[",     "\\!",   "]",     "\\^",   "\\_",
  163.     "`",     "a",     "b",     "c",     "d",     "e",     "f",     "g",
  164.     "h",     "i",     "j",     "k",     "l",     "m",     "n",     "o",
  165.     "p",     "q",     "r",     "s",     "t",     "u",     "v",     "w",
  166.     "x",     "y",     "z",     "\\{",   "\\|",   "\\}",   "\\~",   "\\^?",
  167. };
  168.  
  169. /* Output a character, with translation.  Avoid side effects with this
  170.    macro! */
  171.  
  172. /*
  173.  * Output a TeX command to tab to column "col" (see tgrindmac.tex for a 
  174.  * partial explanation of the bizarre brace arrangement).
  175.  */
  176. #define tabto(col) printf(" %d @TAB\n", col);
  177.  
  178. void
  179. sinitfile()                /* send the init file to output */
  180.  
  181. {
  182.     char    cc;
  183.  
  184.     FILE    *fptr;
  185.  
  186.     if( !(fptr = fopen(INITFILE,"r"))) {
  187.         fprintf(stderr,"Can't open init file (%s)\n",INITFILE);
  188.         exit(1);
  189.     }
  190.  
  191.     while( (cc = getc(fptr)) != -1) putchar(cc);
  192.  
  193.     fclose(fptr);
  194. }
  195.  
  196. void    
  197. outchar(cc)            /* output the char    */
  198.     char     cc;
  199.  
  200. {
  201.     if((cc == '(') || (cc == ')') || (cc == '\\'))
  202.         putchar('\\');
  203.     if(cc == '\n')  {
  204.         outlnum++;
  205.         modechange(0);
  206.         if(!(outlnum % 10) && !procout) {
  207.         printf(" (%d) @N ",reallnum);
  208.             if(incomm)
  209.              printf("@C ");
  210.         }
  211.         procout = 0;
  212.         printf("@NL");
  213.     }
  214.     putchar(cc);
  215. }
  216.  
  217. int
  218. outpsstring(what)            /* output a postscript string */
  219.     char *what;
  220.  
  221. {
  222.     char    cc;
  223.     int    len,x;
  224.  
  225.     len = strlen(what);
  226.  
  227.         printf(" (");
  228.         for(x=0; x < len; x++)  {
  229.         cc = *(what + x);
  230.         if( (cc == '(') || (cc == ')') || (cc == '\\'))
  231.              putchar('\\');
  232.         putchar(cc);
  233.         }
  234.         printf(") ");
  235.     return(0);
  236. }
  237.  
  238. int
  239. modechange(type)            /* purge the current string if any */
  240.     int    type;            /* close out the mode string       */
  241.  
  242.  
  243. {
  244. static    int    oldtype;
  245.  
  246.     if(charmflag)  {
  247.         switch (oldtype) {
  248.     
  249.         case _SMODE : 
  250.             printf(") @S\n");
  251.             break;
  252.         case _SHMODE :
  253.             printf(") @SH\n");
  254.             break;
  255.         case _KMODE :
  256.             printf(") @K\n");
  257.             break;
  258.         case _CMODE :
  259.             printf(") @C\n");
  260.             break;
  261.         case _NMODE :
  262.             printf(") @N\n");
  263.             break;
  264.         default :;
  265.         }            /* end switch */
  266.     }        /* end if        */
  267.     if(type) 
  268.         oldtype = type;
  269.     charmflag = 0;
  270.     return(0);
  271. }
  272.  
  273. void
  274. charmode()            /* begin char mode        */
  275. {
  276.     if(!charmflag) {
  277.         printf(" (");
  278.         charmflag = -1;
  279.     }
  280. }
  281.  
  282. main(argc, argv)
  283.     int argc;
  284.     char *argv[];
  285. {
  286.     char *fname = "", *p;
  287.     char buf[DBUFSIZ];
  288.     char strings[2 * DBUFSIZ];
  289.     char defs[2 * DBUFSIZ];
  290. #ifdef    MSDOS
  291.     struct tm *tmstr;
  292. #else
  293.     struct stat stbuf;
  294. #endif
  295.     FILE    *realfptr;
  296.     int    twomode;
  297.  
  298.     twomode=0;
  299.         realfptr = stdin;
  300.     sinitfile();            /* send the init file    */
  301.  
  302.     argc--, argv++;
  303.     do {
  304.     register char *cp;
  305.     register int i;
  306.  
  307.     if (argc > 0) {
  308.         if (!strcmp(argv[0], "-h")) {
  309.         if (argc == 1) {
  310.             printf("() @Head\n");
  311.             argc--; argv++;
  312.             goto rest;
  313.         }
  314.         putstr( argv[1] );
  315.         printf( "@Head \n" );
  316.         argc--, argv++;
  317.         argc--, argv++;
  318.         if (argc > 0)
  319.             continue;
  320.         goto rest;
  321.         }
  322.       
  323.         /* check for ignore def    */
  324.         if(!strcmp(argv[0],"-id")) {
  325.         ignoredef = argv[1];
  326.         argc--; argv++;
  327.         argc--; argv++;
  328.         continue;
  329.         }
  330.  
  331.             /* -wide for wide 132 column printouts */
  332.         if(!strcmp(argv[0],"-wide")) {
  333.         wide = -1;
  334.         argc--; argv++;
  335.         continue;
  336.         }
  337.  
  338.            /* -2 2 pages per physical page    */
  339.         if(!strcmp(argv[0],"-2")) {
  340.         twomode = -1;
  341.         argc--; argv++;
  342.         continue;
  343.         }
  344.  
  345.         /* take input from the standard place */
  346.         if (!strcmp(argv[0], "-")) {
  347.         argc = 0;
  348.         realfptr = stdin;
  349.         goto rest;
  350.         }
  351.  
  352.         /* indicate no keywords */
  353.         if (!strcmp(argv[0], "-n")) {
  354.         nokeyw++;
  355.         argc--, argv++;
  356.         continue;
  357.         }
  358.  
  359.         /* specify the language */
  360.         if (!strncmp(argv[0], "-l", 2)) {
  361.         language = argv[0]+2;
  362.         argc--, argv++;
  363.         continue;
  364.         }
  365.  
  366.         /* specify the language description file */
  367.         if (!strncmp(argv[0], "-d", 2)) {
  368.         defsfile = argv[1];
  369.         argc--, argv++;
  370.         argc--, argv++;
  371.         continue;
  372.         }
  373.  
  374.         /* open the file for input */
  375.         if ((realfptr = fopen(argv[0], "r")) == NULL) {
  376.         fprintf(stderr,"Error: fopen\n");
  377.         exit(1);
  378.         }
  379.  
  380.         fname = argv[0];
  381.         argc--, argv++;
  382.     }
  383.     rest:
  384.  
  385.     /*
  386.      *  get the  language definition from the defs file
  387.      */
  388.     i = tgetent (defs, language, defsfile);
  389.     if (i == 0) {
  390.         fprintf (stderr, "no entry for language %s\n", language);
  391.         exit (0);
  392.     } else  if (i < 0) {
  393.         fprintf (stderr,  "cannot find vgrindefs file %s\n", defsfile);
  394.         exit (0);
  395.     }
  396.     p = strings;
  397.     if (tgetstr ("kw", &p) == NIL)
  398.         nokeyw = TRUE;
  399.     else  {
  400.         char **cpp;
  401.  
  402.         cpp = l_keywds;
  403.         cp = strings;
  404.         while (*cp) {
  405.         while (*cp == ' ' || *cp =='\t')
  406.             *cp++ = NULL;
  407.         if (*cp)
  408.             *cpp++ = cp;
  409.         while (*cp != ' ' && *cp  != '\t' && *cp)
  410.             cp++;
  411.         }
  412.         *cpp = NIL;
  413.     }
  414.     p = buf;
  415.     l_prcbeg = convexp (tgetstr ("pb", &p));
  416.     p = buf;
  417.     l_combeg = convexp (tgetstr ("cb", &p));
  418.     p = buf;
  419.     l_comend = convexp (tgetstr ("ce", &p));
  420.     p = buf;
  421.     l_acmbeg = convexp (tgetstr ("ab", &p));
  422.     p = buf;
  423.     l_acmend = convexp (tgetstr ("ae", &p));
  424.     p = buf;
  425.     l_strbeg = convexp (tgetstr ("sb", &p));
  426.     p = buf;
  427.     l_strend = convexp (tgetstr ("se", &p));
  428.     p = buf;
  429.     l_blkbeg = convexp (tgetstr ("bb", &p));
  430.     p = buf;
  431.     l_blkend = convexp (tgetstr ("be", &p));
  432.     p = buf;
  433.     l_chrbeg = convexp (tgetstr ("lb", &p));
  434.     p = buf;
  435.     l_chrend = convexp (tgetstr ("le", &p));
  436.     l_escape = '\\';
  437.     l_onecase = tgetflag ("oc");
  438.     if ( l_onecase )
  439.         re_strncmp = lc_strncmp;
  440.     else
  441.         re_strncmp = strncmp;
  442.     l_toplex = tgetflag ("tl");
  443.  
  444.     /* initialize the program */
  445.  
  446.     incomm = FALSE;
  447.     instr = FALSE;
  448.     inchr = FALSE;
  449.     rescaped = FALSE;
  450.     blklevel = 0;
  451.     for (psptr=0; psptr<PSMAX; psptr++) {
  452.         pstack[psptr][0] = NULL;
  453.         plstack[psptr] = 0;
  454.     }
  455.     psptr = -1;
  456. #ifndef    MSDOS
  457. #ifdef AMIGA
  458.     /* SAS's libraries don't return the current date if you
  459.      * ask for the modification date of stdin...
  460.      */
  461.     time(&stbuf.st_mtime);
  462.     cp = ctime(&stbuf.st_mtime);
  463. #else
  464.     fstat(fileno(stdin), &stbuf);
  465.     cp = ctime(&stbuf.st_mtime);
  466. #endif /* Amiga */
  467. #else
  468.     cp = asctime(tmstr = localtim(NULL));
  469. #endif
  470.     cp[10] = '\0';
  471.     cp[16] = '\0';
  472.     cp[24] = '\0';
  473.  
  474.     putstr(fname);
  475.     putstr(cp+11);
  476.     sprintf(buf,"%s %s",cp+4,cp+20);
  477.     putstr(buf);
  478.     printf("@FILE \n");
  479.     if(twomode)
  480.        printf("@DO2\n");        /* order here is important */
  481.     if(wide)
  482.        printf("@WIDE \n");        /* must come after @DO2    */
  483.     printf("@NEWPAGE\n");        /* force the page setup */
  484.     /*
  485.      *    MAIN LOOP!!!
  486.      */
  487.     outlnum = reallnum = 0;
  488.     modechange(_SHMODE);            /* set the show mode */
  489.     while (1) {
  490.         fgets(buf, sizeof buf, realfptr);
  491.         if(feof(realfptr)) {
  492.         fclose(realfptr); 
  493.         break;
  494.         }
  495.         reallnum++;
  496.         if(ignoredef)  {
  497.         if(inignore)  {
  498.                 if(!strncmp(buf,"#endif",6))  
  499.                 inignore = 0;
  500.             continue;
  501.         }
  502.         if(!(strncmp(buf,"#ifdef",6))) {
  503. #ifdef    DEBUG
  504.         fprintf(stderr,"Examining (%s)\n",buf+strlen(buf)-strlen(ignoredef)-1);
  505. #endif
  506.             if(!(strncmp(buf+strlen(buf)-strlen(ignoredef)-1,
  507.                 ignoredef,strlen(ignoredef)))) {
  508.             inignore = -1;
  509.             continue;
  510.             }
  511.         }
  512.         }
  513.     
  514.         cp = buf;
  515.         if (*cp == '\f') {
  516.         printf("@NEXTPAGE \n");
  517.         cp++;
  518.         if (*cp == '\n')/* some people like ^Ls on their own line */
  519.             continue;
  520.         }
  521.         prccont = FALSE;
  522.         putScp(cp);
  523.         if (prccont && (psptr >= 0)) {
  524.         putstr(pstack[psptr]);
  525.         printf("@PROCC\n");
  526.         procout = -1;
  527.         }
  528. #ifdef DEBUG
  529.         fprintf (stderr,"com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
  530. #endif
  531.     }
  532.         if(argc <= 0) break;
  533.     printf("@FLUSHPAGE\n");
  534.     } while (argc > 0);
  535.     printf("@FLUSHPAGE\n%c",4);
  536.     exit(0);
  537. }
  538.  
  539. #define isidchr(c) (isalnum(c) || (c) == '_')
  540.  
  541. void
  542. putScp(os)
  543.     char *os;
  544. {
  545.     register char *s;            /* pointer to unmatched string */
  546.     char *comptr;            /* start of a comment delimiter */
  547.     char *comendptr;            /* end of a comment delimiter */
  548.     char *acmptr;            /* start of an alt. comment delimiter */
  549.     char *acmendptr;            /* end of an alt. comment delimiter */
  550.     char *strptr;            /* start of a string delimiter */
  551.     char *strendptr;            /* end of a string delimiter */
  552.     char *chrptr;            /* start of a char. const delimiter */
  553.     char *chrendptr;            /* end of a char. const delimiter */
  554.     char *blksptr;            /* start of a lexical block start */
  555.     char *blksendptr;            /* end of a lexical block start */
  556.     char *blkeptr;            /* start of a lexical block end */
  557.     char *blkeendptr;            /* end of a lexical block end */
  558.  
  559. #ifdef    DEBUG
  560.     fprintf(stderr,"PutScp    %s\n",os);
  561. #endif
  562.     s = os;
  563.     rstart = os;            /* remember the start for expmatch */
  564.     rescaped = FALSE;
  565.     if (nokeyw || incomm || instr)
  566.     goto skip;
  567.     if (isproc(s)) {
  568.     modechange(0);
  569.     putstr(pname);
  570.     printf("@PROC\n");
  571.     procout = -1;
  572.     if (psptr < PSMAX) {
  573.         ++psptr;
  574.         strncpy (pstack[psptr], pname, PNAMELEN);
  575.         pstack[psptr][PNAMELEN] = NULL;
  576.         plstack[psptr] = blklevel;
  577.     }
  578.     } 
  579. skip:
  580.     do {
  581.     /* check for string, comment, blockstart, etc */
  582.     if (!incomm && !instr && !inchr) {
  583.  
  584.         blkeendptr = expmatch (s, l_blkend, &blkeptr, NIL);
  585.         blksendptr = expmatch (s, l_blkbeg, &blksptr, NIL);
  586.         comendptr = expmatch (s, l_combeg, &comptr, NIL);
  587.         acmendptr = expmatch (s, l_acmbeg, &acmptr, NIL);
  588.         strendptr = expmatch (s, l_strbeg, &strptr, NIL);
  589.         chrendptr = expmatch (s, l_chrbeg, &chrptr, NIL);
  590.  
  591.         /* start of a comment? */
  592.         if (comptr != NIL
  593.           && (strptr  == NIL || comptr < strptr)
  594.           && (acmptr  == NIL || comptr < acmptr)
  595.           && (chrptr  == NIL || comptr < chrptr)
  596.           && (blksptr == NIL || comptr < blksptr)
  597.           && (blkeptr == NIL || comptr < blkeptr)) {
  598.             putKcp (s, comptr-1, FALSE);
  599.             modechange(0);
  600.             printf("@C\n");
  601.             modechange(_SHMODE);
  602.             s = comendptr;
  603.             putKcp (comptr, comendptr-1, FALSE);
  604.             incomm = TRUE;
  605.             comtype = STANDARD;
  606.             continue;
  607.         }
  608.  
  609.         /* start of an alternate-form comment? */
  610.         if (acmptr != NIL
  611.           && (strptr  == NIL || acmptr < strptr)
  612.           && (chrptr  == NIL || acmptr < chrptr)
  613.           && (blksptr == NIL || acmptr < blksptr)
  614.           && (blkeptr == NIL || acmptr < blkeptr)) {
  615.             putKcp (s, acmptr-1, FALSE);
  616.             modechange(0);
  617.             printf("@C\n");
  618.             modechange(_SHMODE);
  619.             s = acmendptr;
  620.             putKcp (acmptr, acmendptr, FALSE);
  621.             incomm = TRUE;
  622.             comtype = ALTERNATE;
  623.             continue;
  624.         }
  625.  
  626.         /* start of a string? */
  627.         if (strptr != NIL
  628.           && (chrptr  == NIL || strptr < chrptr)
  629.           && (blksptr == NIL || strptr < blksptr)
  630.           && (blkeptr == NIL || strptr < blkeptr)) {
  631.             putKcp (s, strptr-1, FALSE);
  632.             modechange(_SMODE);
  633.             s = strendptr;
  634.             putKcp (strptr,strendptr-1, FALSE);
  635.             instr = TRUE;
  636.             continue;
  637.         }
  638.  
  639.         /* start of a character string? */
  640.         if (chrptr != NIL
  641.           && (blksptr == NIL || chrptr < blksptr)
  642.           && (blkeptr == NIL || chrptr < blkeptr)) {
  643.             putKcp (s, chrptr-1, FALSE);
  644.             modechange(_SMODE);
  645.             s = chrendptr;
  646.             putKcp (chrptr, chrendptr-1, FALSE);
  647.             inchr = TRUE;
  648.             continue;
  649.         }
  650.  
  651.         /* end of a lexical block */
  652.         if (blkeptr != NIL) {
  653.         if (blksptr == NIL || blkeptr < blksptr) {
  654.             putKcp (s, blkeendptr - 1, FALSE);
  655.             s = blkeendptr;
  656.             blklevel--;
  657.             if (psptr >= 0 && plstack[psptr] >= blklevel) {
  658.  
  659.             /* end of current procedure */
  660.             blklevel = plstack[psptr];
  661.  
  662.             /* see if we should print the last proc name */
  663.             if (--psptr >= 0)
  664.                 prccont = TRUE;
  665.             else
  666.                 psptr = -1;
  667.             }
  668.             continue;
  669.         }
  670.         }
  671.  
  672.         /* start of a lexical block */
  673.         if (blksptr != NIL) {
  674.         putKcp (s, blksendptr - 1, FALSE);
  675.         s = blksendptr;
  676.         blklevel++;
  677.         continue;
  678.         }
  679.  
  680.     /* check for end of comment */
  681.     } else if (incomm) {
  682.         if ((comendptr = expmatch( s,
  683.                        comtype==STANDARD? l_comend : l_acmend,
  684.                            NIL, NIL)) != NIL) {
  685.         putKcp (s, comendptr-1, TRUE);
  686.         s = comendptr;
  687.         incomm = FALSE;
  688.         modechange(0);
  689.         printf(" @CE\n");
  690.         modechange(_SHMODE);
  691.         } else {
  692.         comptr = s;
  693.         s += strlen(s);
  694.         putKcp (comptr, s-1, TRUE);
  695.         }
  696.         continue;
  697.  
  698.     /* check for end of string */
  699.     } else if (instr) {
  700.         if ((strendptr = expmatch (s, l_strend, NIL, NIL)) != NIL) {
  701.         putKcp (s, strendptr-1, TRUE);
  702.         s = strendptr;
  703.         instr = FALSE;
  704.         modechange(_SHMODE);
  705.         
  706.         } else {
  707.         strptr = s;
  708.         s += strlen(s);
  709.         putKcp (strptr, s-1, TRUE);
  710.         }
  711.         continue;
  712.  
  713.     /* check for end of character string */
  714.     } else if (inchr) {
  715.         if ((chrendptr = expmatch (s, l_chrend, NIL, NIL)) != NIL) {
  716.         putKcp (s, chrendptr-1, TRUE);
  717.         s = chrendptr;
  718.         inchr = FALSE;
  719.         modechange(_SHMODE);
  720.         } else {
  721.         chrptr = s;
  722.         s += strlen(s);
  723.         putKcp (chrptr, s-1, TRUE);
  724.         }
  725.         continue;
  726.     }
  727.  
  728.     /* print out the line */
  729.     chrptr = s;
  730.     s += strlen(s);
  731.     putKcp (chrptr, s-1, FALSE);
  732.  
  733.     } while (*s);
  734. }
  735.  
  736. void
  737. putKcp(start, end, nix)
  738.     register char *start;    /* start of string to write */
  739.     register char *end;    /* end of string to write */
  740.     register boolean nix;    /* true if we should force nokeyw */
  741. {
  742.     register int i, c;
  743.  
  744.     if (nokeyw)
  745.         nix = TRUE;
  746.  
  747.     while (start <= end) {
  748.         c = *start++;
  749.         /* take care of nice tab stops */
  750.         if (c == '\t') {
  751.             while (start <= end && *start == '\t')
  752.                 start++;
  753.             modechange(0);
  754.             tabto(width(rstart, start));
  755.             continue;
  756.         }
  757.         if (!nix && (c == '#' || isidchr(c))) {/* potential keyword */
  758.             start--;
  759.             if (start == rstart || !isidchr(start[-1])) {
  760.                 i = iskw(start);
  761.                 if (i > 0) {
  762.                     modechange(_KMODE);
  763.                     printf(" (");
  764.                     charmflag = -1;
  765.                     while (--i >= 0) {
  766.                         c = *start++;
  767.                         outchar(c);
  768.                     }
  769.                     modechange(_SHMODE);
  770.                     continue;
  771.                 }
  772.             }
  773.             start++;
  774.         }
  775.         charmode();
  776.         outchar(c);
  777.     }
  778. }
  779.  
  780.  
  781. int
  782. width(s, os)
  783.     register char *s, *os;
  784. {
  785.     register int i = 0, c;
  786.  
  787.     while (s < os) {
  788.         c = *s++;
  789.         if (c == '\t') {
  790.             i = (i + 8) &~ 7;
  791.             continue;
  792.         }
  793.         if (c < ' ')
  794.             i += 2;
  795.         else
  796.             i++;
  797.     }
  798.     return (i);
  799. }
  800.  
  801. /* output a string, escaping special characters */
  802. void
  803. putstr(cp)
  804.     register char *cp;
  805. {
  806.     outpsstring(cp);
  807. }
  808.  
  809. /*
  810.  *    look for a process beginning on this line
  811.  */
  812. boolean
  813. isproc(s)
  814.     char *s;
  815. {
  816.     pname[0] = NULL;
  817.     if ((!l_toplex || blklevel == 0)
  818.         && expmatch(s, l_prcbeg, NIL, pname) != NIL)
  819.         return (TRUE);
  820.     return (FALSE);
  821. }
  822.  
  823.  
  824. /*  iskw -    check to see if the next word is a keyword
  825.  */
  826.  
  827. int
  828. iskw(s)
  829.     register char *s;
  830. {
  831.     register char **ss = l_keywds;
  832.     register int i = 1;
  833.     register char *cp = s;
  834.     register int firstc = *s;
  835.  
  836.     while (++cp, isidchr(*cp))
  837.         i++;
  838.     while (cp = *ss++) {
  839.         if (!l_onecase && firstc != *cp)
  840.             continue;
  841.         if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
  842.             return (i);
  843.     }
  844.     return (0);
  845. }
  846.